#include "glm.h"
#include <iostream>

namespace glm
{
	Vec4f operator*(const mat4& m, const Vec4f& v)
	{
		const float x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z + m[0][3] * v.w;
		const float y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z + m[1][3] * v.w;
		const float z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z + m[2][3] * v.w;
		const float w = m[3][0] * v.x + m[3][1] * v.y + m[3][2] * v.z + m[3][3] * v.w;
		return Vec4f(x, y, z, w);
	}
	Vec3f operator*(const mat3& m, const Vec3f& v)
	{
		const float x = m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z;
		const float y = m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z;
        const float z = m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z;
        return Vec3f(x, y, z);
	}
	mat3 Vec3toMat3(const Vec3f& v1, const Vec3f& v2, const Vec3f& v3)
	{
		mat3 res;
		for (int i = 0;i < 3;i++)
		{
			res[i][0] = v1[i];
			res[i][1] = v2[i];
			res[i][2] = v3[i];
		}
		return res;
	}
	float radians(float degrees)
	{
		return degrees * M_PI / 180.0f;;
	}
	mat4 translate(const mat4& matrix, const Vec3f& v)
	{
		mat4 translateMatrix;
		for (int i = 0;i < 3;i++)
		{
			translateMatrix[i][3] = v[i];
		}
		return matrix * translateMatrix;
	}
	mat4 scale(const mat4& matrix, const Vec3f& v)
	{
		mat4 scaleMatrix;
        for (int i = 0;i < 3;i++)
		{
			scaleMatrix[i][i] = v[i];
		}
        return matrix * scaleMatrix;
	}
	mat4 rotate(const mat4& matrix, float angle, const Vec3f& axis) 
	{
		// 将角度转换为弧度
		float rad = radians(angle);
		float cosTheta = cos(rad);
		float sinTheta = sin(rad);
		float oneMinusCos = 1.0f - cosTheta;

		// 归一化旋转轴
		Vec3f normalizedAxis = axis.normalized();
		float rx = normalizedAxis.x;
		float ry = normalizedAxis.y;
		float rz = normalizedAxis.z;

		mat4 rotateMatrix;

		// 第一列
		rotateMatrix[0][0] = cosTheta + rx * rx * oneMinusCos;
		rotateMatrix[0][1] = rx * ry * oneMinusCos + rz * sinTheta;
		rotateMatrix[0][2] = rx * rz * oneMinusCos - ry * sinTheta;

		// 第二列
		rotateMatrix[1][0] = rx * ry * oneMinusCos - rz * sinTheta;
		rotateMatrix[1][1] = cosTheta + ry * ry * oneMinusCos;
		rotateMatrix[1][2] = ry * rz * oneMinusCos + rx * sinTheta;

		// 第三列
		rotateMatrix[2][0] = rx * rz * oneMinusCos + ry * sinTheta;
		rotateMatrix[2][1] = ry * rz * oneMinusCos - rx * sinTheta;
		rotateMatrix[2][2] = cosTheta + rz * rz * oneMinusCos;

		return matrix * rotateMatrix;
	}
	mat4 lookAt(const Vec3f& eye, const Vec3f& center, const Vec3f& up)
	{
		Vec3f D = (center - eye).normalized();
		Vec3f R = D.cross(up).normalized();
		Vec3f U = R.cross(D);

		mat4 viewMatrix;

        viewMatrix[0][0] = R.x;
        viewMatrix[0][1] = R.y;
        viewMatrix[0][2] = R.z;
        viewMatrix[1][0] = U.x;
        viewMatrix[1][1] = U.y;
		viewMatrix[1][2] = U.z;
        viewMatrix[2][0] = -D.x;
		viewMatrix[2][1] = -D.y;
        viewMatrix[2][2] = -D.z;
		viewMatrix[0][3] = -R.dot(eye);
		viewMatrix[1][3] = -U.dot(eye);
		viewMatrix[2][3] = D.dot(eye);

		return viewMatrix;
	}
	mat4 ortho(float left, float right, float bottom, float top, float n, float f)
	{
		mat4 orthoMatrix;

		// 计算缩放分量
		orthoMatrix[0][0] = 2.0f / (right - left);
		orthoMatrix[1][1] = 2.0f / (top - bottom);
		orthoMatrix[2][2] = 2.0f / (n - f); // z轴方向反转

		// 计算平移分量
		orthoMatrix[0][3] = (left + right) / (left - right);
		orthoMatrix[1][3] = (bottom + top) / (bottom - top);
		orthoMatrix[2][3] = (n + f) / (n - f);

		return orthoMatrix;
	}
	mat4 perspective(float fov, float aspect, float n, float f)
	{
		mat4 proj;
		float tanHalfFov = tan(glm::radians(fov) / 2);
		proj[0][0] = 1 / (aspect * tanHalfFov);
		proj[1][1] = 1 / tanHalfFov;
		proj[2][2] = (f + n) / (n - f);
		proj[2][3] = 2 * n * f / (n - f);
		proj[3][2] = -1;
		return proj;
	}
	mat4 viewport(float w, float h)
	{
        mat4 viewportMatrix;
        viewportMatrix[0][0] = w / 2;
        viewportMatrix[1][1] = h / 2;
        viewportMatrix[2][2] = 0.5;
        viewportMatrix[0][3] = w / 2;
        viewportMatrix[1][3] = h / 2;
        viewportMatrix[2][3] = 0.5;
        return viewportMatrix;
	}
	Vec3f barycentric(const Vec3f& A, const Vec3f& B, const Vec3f& C, const Vec3f& P)
	{
		Vec3f a = { C.x - A.x, B.x - A.x, A.x - P.x };
		Vec3f b = { C.y - A.y, B.y - A.y, A.y - P.y };
		Vec3f u = a ^ b;
		// 三角形退化
		if (IsNearlyZero(u.z))
		{
			return Vec3f(-1, 1, 1);
		}

		return Vec3f(1.f - (u.x + u.y) / u.z, u.y / u.z, u.x / u.z);
	}
	Vec3f barycentricCorrect(const Vec3f& A, const Vec3f& B, const Vec3f& C, const Vec3f& P)
	{
		if (IsNearlyZero(A.z) && IsNearlyZero(B.z) && IsNearlyZero(C.z))
		{
            std::cout << "glm::barycentricCorrect A, B, C w is zero!" << std::endl;
			return barycentric(A, B, C, P);
		}

		Vec3f bc = barycentric(A, B, C, P);
		float det = bc.x/A.z + bc.y/B.z + bc.z/C.z;
        if (IsNearlyZero(det))
		{
            std::cout << "glm::barycentricCorrect det is zero" << std::endl;
			return bc;
		}
		bc.x = bc.x / A.z / det;
        bc.y = bc.y / B.z / det;
        bc.z = bc.z / C.z / det;
		return bc;
	}
	Vec3f tangent(std::pair<Vec3f, Vec2f> p1, std::pair<Vec3f, Vec2f> p2, std::pair<Vec3f, Vec2f> p3)
	{
		Vec3f t;

		Vec3f edge1 = p2.first - p1.first;
		Vec3f edge2 = p3.first - p1.first;
		Vec2f deltaUV1 = p2.second - p1.second;
		Vec2f deltaUV2 = p3.second - p1.second;

		float det = deltaUV1.x * deltaUV2.y - deltaUV2.x * deltaUV1.y;
		// 判断分母是否为0，若为0返回一个默认的值
		if (IsNearlyZero(det))
		{
			std::cout << "glm::tangent det is zero" << std::endl;
			return Vec3f(1, 0, 0);
		}

		t = (edge1 * deltaUV2.y - edge2 * deltaUV1.y) / det;

		return t;
	}
	Vec3f reflect(const Vec3f& I, const Vec3f& N)
	{
		return I - 2 * N.dot(I) * N;;
	}
}

template class glm::mat<4>;
template class glm::mat<3>;
